home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / mail / mush-7.1.1 / curses.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-05-02  |  27.8 KB  |  1,016 lines

  1. /* @(#)curses.c    (c) copyright 3/18/87 (Dan Heller) */
  2.  
  3. /* curses.c -- routine to deal with the curses interface */
  4. #ifdef CURSES
  5.  
  6. #include "mush.h"
  7. #include "bindings.h"
  8.  
  9. curses_init(argc, argv)
  10. register char **argv;
  11. {
  12.     char buf[80];
  13.     extern char *UP, ttytype[];
  14.  
  15.     if (argv && *++argv && !strcmp(*argv, "-?"))
  16.     return help(0, "curses", cmd_help);
  17. #ifdef SUNTOOL
  18.     if (istool) {
  19.     print("Sorry, can't change to curses mode from tool.\n");
  20.     return -1;
  21.     } else
  22. #endif /* SUNTOOL */
  23.     if (!is_shell) {
  24.     /*
  25.      * Can't start curses, but we can prepare to.
  26.      * Also allow -C switch to be shut off.
  27.      */
  28.     if (argv && *argv && !lcase_strncmp(*argv, "off", -1))
  29.         turnoff(glob_flags, PRE_CURSES);
  30.     else
  31.         turnon(glob_flags, PRE_CURSES);
  32.     return 0;
  33.     } else if (argc && (iscurses || ison(glob_flags, PRE_CURSES))) {
  34.     print("You are already using curses mode.\n");
  35.     return -1;
  36.     } else if (ison(glob_flags, IS_GETTING)) {
  37.     print("Finish your letter first.\n");
  38.     return -1;
  39.     }
  40.  
  41. #ifndef attrset        /* terminfo version of curses */
  42.     /* you can not start curses in no echo mode.. must be in normal mode */
  43.     echom();
  44.     nocrmode();
  45. #endif /* attrset */
  46.     (void) initscr();
  47. #ifdef SIGCONT
  48.     /* initscr will play with signals -- make sure they're set right. */
  49.     (void) signal(SIGTSTP, stop_start);
  50.     (void) signal(SIGCONT, stop_start);
  51. #endif /* SIGCONT */
  52. #if !defined(SYSV) && !defined(USG)
  53.     if (!UP || !*UP)
  54. #else /* ~SYSV && ~USG */
  55.     if (!stdscr)
  56. #endif /* ~SYSV && ~USG */
  57.          {
  58.     print("Terminal type %s can not use the curses interface.\n", ttytype);
  59.     return -1;
  60.     }
  61.     iscurses = TRUE;
  62.     noechom(); /* reset tty state -- */
  63.     crmode(); /* do not use "echo_on/off()" */
  64.     scrollok(stdscr, TRUE);
  65.     /* if the user hasn't set his screen explicitly, set it for him */
  66.     set_screen_size();
  67.     if (crt > LINES - 1 || !do_set(set_options, "crt")) {
  68.     crt = LINES;
  69.     (void)cmd_line(sprintf(buf, "\\set screen = %d crt = %d", screen, crt),
  70.         msg_list);
  71.     } else
  72.     (void)cmd_line(sprintf(buf, "\\set screen = %d", screen), msg_list);
  73.     if (argc) {
  74.     (void) cmd_line(sprintf(buf, "\\headers %d", current_msg+1), msg_list);
  75.     (void) curses_help_msg(TRUE);
  76.     }
  77.     if (!do_set(set_options, "no_reverse"))
  78.     turnon(glob_flags, REV_VIDEO);
  79.     turnoff(glob_flags, CONT_PRNT);
  80.     return 0; /* doesn't affect messages */
  81. }
  82.  
  83. struct cmd_map *active_cmd;    /* See bindings.h for description */
  84.  
  85. /*
  86.  * get input in cbreak mode and execute the appropriate command.
  87.  * when the command is done (usually), the user is prompted to
  88.  * hit any key to continue. At this point, the user may enter a
  89.  * new command so no screen refreshing needs to be done. This
  90.  * new command is returned to caller and may be passed back.
  91.  *
  92.  * The flag CNTD_CMD (continued command) is set if
  93.  * this routine is called with the passed parameter (c) != 0. If
  94.  * so, then the character passed is the character input by the
  95.  * user at the last "hit return" prompt indicating that he wants
  96.  * to execute a new command and not draw the screen.
  97.  *
  98.  * CNTD_CMD is also set if the command that the user invokes
  99.  * causes any sort of output that requires a screen refresh.  The
  100.  * variable redo is set to 1 if the header page not only requires
  101.  * redrawing, but updating ... (new call to do_hdrs)
  102.  *
  103.  * calls that say: print("%s", compose_hdr(current_msg)) are constructed
  104.  * that way because if the header has a `%' in it, then print will try to
  105.  * expand it.
  106.  */
  107. curses_command(c)
  108. register int c;
  109. {
  110.     char    buf[BUFSIZ], file[128], list[128];
  111.     int     n, curlin;
  112.     static int  redo = 0;  /* set if headers should be redrawn */
  113.  
  114.     if (c != 0)
  115.     turnon(glob_flags, CNTD_CMD);
  116.     else
  117.     turnoff(glob_flags, CNTD_CMD);
  118.     clear_msg_list(msg_list); /* play it safe */
  119.     if (isoff(glob_flags, CNTD_CMD)) {
  120.     (void) check_new_mail();
  121.     curlin = max(1, current_msg - n_array[0] + 1);
  122.     scrn_line(curlin, buf);
  123.     if (ison(glob_flags, REV_VIDEO) && msg_cnt)
  124.         STANDOUT(curlin, 0, buf);
  125.     mail_status(0);
  126.     move(curlin, 0), refresh();
  127.     /* reprint to remove reverse video from current line (don't refresh) */
  128.     if (ison(glob_flags, REV_VIDEO))
  129.         mvaddstr(curlin, 0, buf);
  130.     c = getcmd(); /* get input AFTER line redrawn without reverse video */
  131.     }
  132.     buf[0] = list[0] = file[0] = '\0';
  133.  
  134.     if (c == C_WRITE_LIST || c == C_SAVE_LIST || c == C_COPY_LIST
  135.        || c == C_DELETE_LIST || c == C_UNDEL_LIST) {
  136.     if (msg_cnt < 1) {
  137.         mac_flush();
  138.         print("Not enough messages.");
  139.         c = C_NULL;
  140.     } else if (c == C_DELETE_LIST && ison(glob_flags, READ_ONLY)) {
  141.         mac_flush();
  142.         print("Folder is read-only.");
  143.         c = C_NULL;
  144.     } else if (!curses_msg_list(sprintf(buf, "%s msg list: ",
  145.         (c == C_WRITE_LIST)? "write" : (c == C_SAVE_LIST)?  "save" :
  146.         (c == C_COPY_LIST)? "copy" :
  147.         (c == C_DELETE_LIST)? "delete" : "undelete"), list, msg_list))
  148.         c = C_NULL;
  149.     if (ison(glob_flags, CNTD_CMD))
  150.         putchar('\n');
  151.     }
  152.  
  153.     /* first do non-mail command type stuff */
  154.     switch (c) {
  155.     case C_ERROR :
  156.         bell();
  157.         mac_flush();
  158.  
  159.     when C_NULL :
  160.         if (isoff(glob_flags, CNTD_CMD))
  161.         bell();
  162.  
  163.     /* goto a specific message number */
  164.     when C_GOTO_MSG :
  165.         if (curses_msg_list(strcpy(buf, "goto msg: "), list, msg_list)) {
  166.         /*
  167.          * Reset the current message in case a 
  168.          * backquoted command (like `from`) changed it
  169.          */
  170.         n = current_msg;
  171.         do if (++n >= msg_cnt)
  172.             n = 0;
  173.         while (n != current_msg && !msg_bit(msg_list, n));
  174.         if (n == current_msg && !msg_bit(msg_list, n)) {
  175.             mac_flush(); /* bail out if in macro processing */
  176.             print("Message not found.");
  177.         }
  178.         else if ((current_msg = n) < n_array[0]
  179.             || n > n_array[screen-1])
  180.             redo = 1;
  181.         } else {
  182.         mac_flush();
  183.         bell();
  184.         }
  185.         if (ison(glob_flags, CNTD_CMD) && msg_cnt)
  186.         print("%-.*s", COLS-2, compose_hdr(current_msg));
  187.         if (ison(glob_flags, CNTD_CMD))
  188.         putchar('\n');
  189.  
  190.     /* screen optimization stuff */
  191.     when C_REVERSE :
  192.         if (ison(glob_flags, REV_VIDEO))
  193.         turnoff(glob_flags, REV_VIDEO);
  194.         else
  195.         turnon(glob_flags, REV_VIDEO);
  196.  
  197.     when C_REDRAW : redo = 1;
  198.  
  199.     /*
  200.      * screen movement
  201.      */
  202.     when C_NEXT_MSG :
  203.         if (current_msg + 2 > msg_cnt ||
  204.         isoff(glob_flags, CNTD_CMD) && curlin == LINES-2) {
  205.         mac_flush();    /* Bail out if in macro processing */
  206.         bell();        /* reached the end */
  207.         } else {
  208.         if (ison(glob_flags, CNTD_CMD)) {
  209.             if (++current_msg > n_array[screen-1])
  210.             redo = 1;
  211.             print("%-.*s", COLS-2, compose_hdr(current_msg));
  212.             putchar('\n');
  213.         } else {
  214.             if (++current_msg > n_array[screen-1])
  215.             n_array[screen++] = current_msg;
  216.             move(++curlin, 0);
  217.             printw("%-.*s", COLS-2, compose_hdr(current_msg));
  218.             clrtoeol();
  219.         }
  220.         }
  221.  
  222.     when C_PREV_MSG :
  223.         if (isoff(glob_flags, CNTD_CMD) && curlin == 1 || current_msg == 0)
  224.         {
  225.         mac_flush();    /* Bail out if in macro processing */
  226.         bell();      /* at the beginning */
  227.         } else {
  228.         if (--current_msg < n_array[0])
  229.             redo = 1;
  230.         if (ison(glob_flags, CNTD_CMD)) {
  231.             print("%-.*s", COLS-2, compose_hdr(current_msg));
  232.             putchar('\n');
  233.         }
  234.         }
  235.  
  236.     when C_FIRST_MSG : case C_LAST_MSG :
  237.         if (!msg_cnt) {
  238.         mac_flush();
  239.         bell();
  240.         break;
  241.         }
  242.         n = current_msg;
  243.         move(LINES-1, 0), refresh();
  244.         if (c == C_FIRST_MSG && (current_msg = 0) < n_array[0] ||
  245.         c == C_LAST_MSG && (current_msg = msg_cnt-1)> n_array[screen-1])
  246.         if (isoff(glob_flags, CNTD_CMD))
  247.             (void) cmd_line(sprintf(buf, "\\headers %d", current_msg+1),
  248.                  msg_list);
  249.         else
  250.             redo = 1;
  251.         if (ison(glob_flags, CNTD_CMD) && n != current_msg)
  252.         print("%-.*s", COLS-2, compose_hdr(current_msg)), putchar('\n');
  253.  
  254.     /* top and bottom of headers screen */
  255.     when C_TOP_PAGE : case C_BOTTOM_PAGE :
  256.         if (msg_cnt && isoff(glob_flags, CNTD_CMD))
  257.         if (c == C_TOP_PAGE)
  258.             current_msg = n_array[0];
  259.         else
  260.             current_msg = min(n_array[screen-1], msg_cnt-1);
  261.         else {
  262.         mac_flush();
  263.         bell();
  264.         }
  265.  
  266.     when C_NEXT_SCREEN : /* next page */
  267.         move(LINES-1, 0), refresh();
  268.         if (msg_cnt-1 > n_array[screen-1]) {
  269.         clear();
  270.         set_screen_size();
  271.         (void) cmd_line(strcpy(buf, "\\headers +"), msg_list);
  272.         if (current_msg < n_array[0])
  273.             current_msg = n_array[0];
  274.         (void) curses_help_msg(TRUE);
  275.         return redo = 0;
  276.         } else {
  277.         mac_flush();
  278.         bell();
  279.         }
  280.  
  281.     when C_PREV_SCREEN : /* previous page */
  282.         move(LINES-1, 0), refresh();
  283.         if (n_array[0] > 0) {
  284.         clear();
  285.         set_screen_size();
  286.         (void) cmd_line(strcpy(buf, "\\headers -"), msg_list);
  287.         if (current_msg > n_array[screen-1])
  288.             current_msg = n_array[screen-1];
  289.         (void) curses_help_msg(TRUE);
  290.         return redo = 0;
  291.         } else {
  292.         mac_flush();
  293.         bell();
  294.         }
  295.  
  296.     /* read from/save to record file (.mushrc) */
  297.     when C_SOURCE : case C_SAVEOPTS : {
  298.         int argc;
  299.         char *argv[3];
  300.         print("%s filename [default]: ",
  301.         (c == C_SOURCE)? "source" : "save options to");
  302.         argc = Getstr(file, LINES-40, 0);
  303.         clr_bot_line();
  304.         if (argc < 0)
  305.         break;
  306.         if (argc > 0)
  307.         argv[1] = file, argc = 2;
  308.         else
  309.         argc = 1;
  310.         argv[argc] = NULL;
  311.         turnon(glob_flags, PRE_CURSES);
  312.         if (c == C_SOURCE) {
  313.         (void) source(argc, argv);
  314.         mac_flush(); /* can't change things in mid-macro */
  315.         redo = isoff(glob_flags, CNTD_CMD);
  316.         } else
  317.         (void) save_opts(argc, argv);
  318.         turnoff(glob_flags, PRE_CURSES);
  319.     }
  320.  
  321.     /*
  322.      * search commands
  323.      */
  324.     when C_NEXT_SEARCH : case C_PREV_SEARCH : case C_CONT_SEARCH :
  325.         if (c != C_CONT_SEARCH)
  326.         c = search(0 + (c == C_PREV_SEARCH));
  327.         else
  328.         c = search(-1);
  329.         if (ison(glob_flags, CNTD_CMD))
  330.         putchar('\n');
  331.         if (c == 0)
  332.         break;
  333.         if (ison(glob_flags, CNTD_CMD))
  334.         print("%-.*s",COLS-2, compose_hdr(current_msg)), putchar('\n');
  335.         if (n_array[0] > current_msg || n_array[screen-1] < current_msg) {
  336.         redo = 1;
  337.         if (isoff(glob_flags, CNTD_CMD))
  338.             (void) cmd_line(sprintf(buf, "\\headers %d",
  339.                         current_msg+1), msg_list);
  340.         }
  341.  
  342.     /*
  343.      * actions on messages
  344.      */
  345.     /* delete/undelete */
  346.     when C_DELETE_MSG : case C_DELETE_LIST :
  347.     case C_UNDEL_MSG : case C_UNDEL_LIST :
  348.         if (!msg_cnt) {
  349.         print("No messages.");
  350.         if (ison(glob_flags, CNTD_CMD))
  351.             putchar('\n');
  352.         break;
  353.         }
  354.         if (ison(glob_flags, READ_ONLY)) {
  355.         mac_flush();
  356.         print("Folder is read-only.");
  357.         if (ison(glob_flags, CNTD_CMD))
  358.             putchar('\n');
  359.         break;
  360.         }
  361.         Debug("current message = %d", current_msg + 1);
  362.         if (!*list)
  363.         set_msg_bit(msg_list, current_msg);
  364.         turnon(glob_flags, DO_UPDATE);
  365.         for (n = 0; n < msg_cnt; n++)
  366.         if (msg_bit(msg_list, n)) {
  367.             if (c == C_DELETE_MSG || c == C_DELETE_LIST)
  368.             turnon(msg[n].m_flags, DELETE);
  369.             else
  370.             turnoff(msg[n].m_flags, DELETE);
  371.             if (isoff(glob_flags, CNTD_CMD) && (msg_cnt < screen ||
  372.             n >= n_array[0] && n <= n_array[screen-1])) {
  373.             move(max(1, n - n_array[0] + 1), 0);
  374.             printw("%-.*s", COLS-1, compose_hdr(n));
  375.             } else
  376.             redo = 1;
  377.         }
  378.         if (ison(glob_flags, CNTD_CMD) || *list) {
  379.         /* print(), THEN putchar() -- overwrite line */
  380.         if (ison(glob_flags, CNTD_CMD)) {
  381.             print("%sdeleted %s",
  382.             (c == C_DELETE_MSG || c == C_DELETE_LIST)? "":"un", list);
  383.             putchar('\n');
  384.         }
  385.         if (c == C_DELETE_MSG || c == C_DELETE_LIST) {
  386.             if (ison(msg[current_msg].m_flags, DELETE) ||
  387.                 ison(msg[current_msg].m_flags, SAVED))
  388.             (void) next_msg();
  389.             if (isoff(msg[current_msg].m_flags, DELETE) &&
  390.                 do_set(set_options, "autoprint"))
  391.             return C_DISPLAY_MSG;
  392.         }
  393.         if (ison(glob_flags, CNTD_CMD))
  394.             puts(compose_hdr(current_msg));
  395.         else if (current_msg < n_array[0]
  396.             || current_msg > n_array[screen-1])
  397.             redo = 1;
  398.         }
  399.  
  400.     /*
  401.      * write/save messages.  If a list is necessary, the user already
  402.      * entered it above since he must have used a capital letter. If so,
  403.      * list will contain good data (already been validated above).
  404.      * if a list is given, set iscurses to 0 so that print statements
  405.      * will scroll and the user sees the multiple output. else, one
  406.      * line can go on the bottom line just fine.
  407.      */
  408.     when C_WRITE_MSG : case C_SAVE_MSG : case C_COPY_MSG :
  409.     case C_WRITE_LIST : case C_SAVE_LIST : case C_COPY_LIST : {
  410.         register char *p =
  411.         (c == C_WRITE_MSG || c == C_WRITE_LIST)? "write" :
  412.         (c == C_SAVE_MSG  || c == C_SAVE_LIST)? "save" : "copy";
  413.         if (!msg_cnt) {
  414.         print("No messages.");
  415.         if (ison(glob_flags, CNTD_CMD))
  416.             putchar('\n');
  417.         break;
  418.         }
  419.         print(sprintf(buf, "filename to %s%s: ", p,
  420.         (c != C_WRITE_MSG && c != C_WRITE_LIST)? " [mbox]" : ""));
  421.         if (Getstr(file, COLS-1-strlen(buf), 0) >= 0) {
  422.         char *argv[3];
  423.         clr_bot_line();
  424.         argv[0] = strcpy(buf, p);
  425.         p = file; skipspaces(0);
  426.         argv[1] = (*p) ? p : NULL;
  427.         argv[2] = NULL;
  428.         if (!*list)
  429.             set_msg_bit(msg_list, current_msg);
  430.         move(LINES-1, 0), refresh();
  431.         if (*list)
  432.             iscurses = FALSE;
  433.         /* Turn on piping to make save_msg look at msg_list */
  434.         turnon(glob_flags, IS_PIPE);
  435.         if (save_msg(1 + (*file != '\0'), argv, msg_list) < 0)
  436.             *list = 0;
  437.         turnoff(glob_flags, IS_PIPE);
  438.         if (ison(glob_flags, CNTD_CMD))
  439.             redo = 1, putchar('\n'), puts(compose_hdr(current_msg));
  440.         if (*list)
  441.             iscurses = redo = TRUE, turnon(glob_flags, CNTD_CMD);
  442.         else if (isoff(glob_flags, CNTD_CMD) && msg_cnt) {
  443.             move(curlin, 0);
  444.             printw("%-.*s", COLS-1, compose_hdr(current_msg));
  445.             }
  446.         } else {
  447.         print("No messages saved.");
  448.         if (ison(glob_flags, CNTD_CMD))
  449.             putchar('\n');
  450.         }
  451.     }
  452.  
  453.     /* preserve message */
  454.     when C_PRESERVE :
  455.         if (!msg_cnt) {
  456.         print("No messages.");
  457.         if (ison(glob_flags, CNTD_CMD))
  458.             putchar('\n');
  459.         break;
  460.         }
  461.         if (ison(msg[current_msg].m_flags, PRESERVE))
  462.         turnoff(msg[current_msg].m_flags, PRESERVE);
  463.         else
  464.         turnon(msg[current_msg].m_flags, PRESERVE);
  465.         turnon(glob_flags, DO_UPDATE);
  466.         if (ison(glob_flags, CNTD_CMD)) {
  467.         wprint("%-.*s\n", COLS-1, compose_hdr(current_msg));
  468.         redo = 1;
  469.         } else {
  470.         move(curlin, 0);
  471.         printw("%-.*s", COLS-1, compose_hdr(current_msg));
  472.         }
  473.  
  474.     /* order messages (sort) and redisplay the headers */
  475.     when C_SORT : case C_REV_SORT :
  476.         (void) strcpy(file, "sort");
  477.         if (c == C_REV_SORT) {
  478.         print("Reverse "), turnon(glob_flags, CONT_PRNT);
  479.         (void) strcat(file, " -");
  480.         }
  481.         print(
  482.         "Order messages by [author, date, length, Status, subject]: "
  483.         );
  484.         if ((c = m_getchar()) == 'a' || c == 'd' || c == 'l' ||
  485.             c == 'S' || c == 's' || c == 'R') {
  486.         print("reordering messages...");
  487.         (void) cmd_line(sprintf(buf, "%s %c", file, c), msg_list);
  488.         print_more("done.");
  489.         if (ison(glob_flags, CNTD_CMD))
  490.             putchar('\n'), puts(compose_hdr(current_msg));
  491.         redo = 1;
  492.         } else
  493.         clr_bot_line();
  494.  
  495.     when C_QUIT_HARD :
  496.         (void) mush_quit(0, DUBL_NULL);
  497.         redo = 1; /* new mail must have come in */
  498.  
  499.     /* quit or update -- vrfy_update (returns 1 if updated) */
  500.     when C_QUIT : case C_UPDATE : {
  501.         clr_bot_line();
  502.         redo = (c == C_UPDATE);
  503.         if (!vrfy_update(&redo))
  504.         if (c == C_UPDATE)
  505.             break;
  506.         if (isoff(glob_flags, CNTD_CMD))
  507.         (void) cmd_line(sprintf(buf, "\\headers %d", current_msg+1),
  508.                 msg_list);
  509.     }
  510.  
  511.     when C_EXIT : case C_EXIT_HARD :
  512.         clr_bot_line();
  513.         iscurses = FALSE;
  514.         if (c != C_EXIT && c != C_EXIT_HARD)
  515.         putchar('\n');
  516.         cleanup(0);
  517.  
  518.     /* change to a new folder */
  519.     when C_FOLDER :
  520.         for (;;) {
  521.         SIGRET (*oldint)(), (*oldquit)();
  522.         on_intr();
  523.         print("New folder (?=list): ");
  524.         c = Getstr(file, COLS-22, 0);
  525.         off_intr();
  526.         if (c > 0) {
  527.             if (!strcmp(file, "?")) {
  528.             clr_bot_line();
  529.             iscurses = 0;
  530.             puts("folders in your folder directory:");
  531.             (void) cmd_line(strcpy(buf, "\\folders"), msg_list);
  532.     puts("Precede folder names with a +. `%' to specify system mailbox.");
  533.             turnon(glob_flags, CNTD_CMD), iscurses = 1;
  534.             continue;
  535.             }
  536.             clearok(stdscr, FALSE);
  537.             /* if vrfy_update doesn't verify, but folder command fails,
  538.              * then we need to reset the updatability of current folder
  539.              */
  540.             c = (ison(glob_flags, DO_UPDATE))? TRUE : FALSE;
  541.             if (strcmp(file, "-?")) {
  542.             redo = 1; /* so vrfy_update() won't quit */
  543.             (void) vrfy_update(&redo);
  544.             }
  545.             move(LINES-1, 0), refresh();
  546.             if (cmd_line(sprintf(buf, "folder ! -N %s", file),
  547.                  msg_list) == -1) {
  548.             if (c) /* remember state of updatability of folder */
  549.                 turnon(glob_flags, DO_UPDATE);
  550.             if (ison(glob_flags, CNTD_CMD))
  551.                 putchar('\n');
  552.             } else
  553.             redo = 1, turnoff(glob_flags, CNTD_CMD);
  554.             break;
  555.         } else {
  556.             print("\"%s\" unchanged.", mailfile);
  557.             if (ison(glob_flags, CNTD_CMD))
  558.             putchar('\n');
  559.             break;
  560.         }
  561.         }
  562.  
  563.     /* shell escape */
  564.     when C_SHELL_ESC :
  565.         print("Shell command: ");
  566.         if (Getstr(file, COLS-24, 0) < 0)
  567.         clr_bot_line();
  568.         else {
  569.         putchar('\n');
  570.         iscurses = FALSE;
  571.         (void) cmd_line(sprintf(buf, "sh %s", file), msg_list);
  572.         iscurses = TRUE;
  573.         turnon(glob_flags, CNTD_CMD);
  574.         }
  575.  
  576.     /* do a line-mode like command */
  577.     when C_CURSES_ESC :
  578.         print(":");
  579.         if (Getstr(buf, COLS-2, 0) < 0)
  580.         break;
  581.         putchar('\n');
  582.         iscurses = FALSE;
  583.         if (!*buf) {
  584.         /* return -1 because iscurses = 0 is not enough! */
  585.         redo = 0;
  586.         endwin(); /* this turns echoing back on! */
  587.         echo_off();
  588.         return -1;
  589.         }
  590.         /* The "source" and "curses" commands need some indication
  591.          * that we are in curses mode, so use the PRE_CURSES flag.
  592.          */
  593.         turnon(glob_flags, PRE_CURSES);
  594.         (void) cmd_line(buf, msg_list);
  595.         /* they may have affected message status or had text output */
  596.         turnon(glob_flags, CNTD_CMD), redo = 1;
  597.         turnoff(glob_flags, PRE_CURSES);
  598.         iscurses = TRUE;
  599.         if (msg_cnt)
  600.         puts(compose_hdr(current_msg));
  601.  
  602.     /* send message to printer, redo to display 'p' status */
  603.     when C_PRINT_MSG : redo = (lpr(0, DUBL_NULL, msg_list) == 0);
  604.  
  605.     /* cd */
  606.     when C_CHDIR :
  607.         print("chdir to [~]: ");
  608.         if (Getstr(file, COLS-12, 0) < 0)
  609.         break;
  610.         clr_bot_line();
  611.         (void) cmd_line(sprintf(buf, "cd %s", file), msg_list);
  612.         if (ison(glob_flags, CNTD_CMD))
  613.         putchar('\n');
  614.  
  615.     /* variable settings */
  616.     when C_VAR_SET : case C_IGNORE : case C_ALIAS : case C_OWN_HDR :
  617.         curs_vars(c); /* CNTD_CMD is reset if there's output! */
  618.  
  619.     when C_VERSION :
  620.         (void) do_version();
  621.         if (ison(glob_flags, CNTD_CMD))
  622.         putchar('\n');
  623.  
  624.     when C_MAIL_FLAGS :
  625.         print("flags [-?]: ");
  626.         if ((c = Getstr(file, COLS-12, 0)) < 0)
  627.         break;
  628.         putchar('\n');
  629.         if (c == 0)
  630.         (void) strcpy(file, "-?");
  631.         else
  632.         redo = 1; /* In case of -f flag, to display the 'f' status */
  633.     /* Fall thru */
  634.     case C_MAIL : {
  635.         u_long flgs = glob_flags;
  636.         turnon(glob_flags, IGN_BANG);
  637.         clr_bot_line();
  638.         iscurses = FALSE;
  639.         (void) cmd_line(sprintf(buf, "mail %s", file), msg_list);
  640.         glob_flags = flgs;
  641.         iscurses = TRUE, turnon(glob_flags, CNTD_CMD);
  642.         if (msg_cnt)
  643.         print("%-.*s", COLS-2, compose_hdr(current_msg)), putchar('\n');
  644.     }
  645.  
  646.     /* reply to mail */
  647.     when C_REPLY_SENDER : case C_REPLY_ALL : {
  648.         register char *p = (c == C_REPLY_ALL)? "replyall" : "replysender";
  649.         clr_bot_line();
  650.         iscurses = FALSE;
  651.         if (isoff(msg[current_msg].m_flags, REPLIED))
  652.         redo = 1;
  653.         (void) cmd_line(sprintf(buf, "%s %d", p, current_msg+1),
  654.         msg_list);
  655.         if (msg_cnt)
  656.         puts(compose_hdr(current_msg));
  657.         iscurses = TRUE, turnon(glob_flags, CNTD_CMD);
  658.     }
  659.  
  660.     /* type out a message */
  661.     when C_DISPLAY_MSG : case C_TOP_MSG : case C_DISPLAY_NEXT :
  662.         if (!msg_cnt ||
  663.         c != C_DISPLAY_NEXT && ison(msg[current_msg].m_flags, DELETE)) {
  664.         if (!msg_cnt)
  665.             print("No messages.");
  666.         else
  667.             print("Message %d deleted; type 'u' to undelete.",
  668.                       current_msg+1);
  669.         if (ison(glob_flags, CNTD_CMD))
  670.             putchar('\n');
  671.         break;
  672.         }
  673.         clr_bot_line();
  674.         iscurses = FALSE;
  675.         if (ison(glob_flags, CNTD_CMD))
  676.         putchar('\n');
  677.         if (c == C_DISPLAY_MSG)
  678.         c = cmd_line(strcpy(buf, "type"), msg_list);
  679.         else if (c == C_TOP_MSG)
  680.         c = cmd_line(strcpy(buf, "top"), msg_list);
  681.         else {
  682.         /* "next" screws up the screen whether it displays or not */
  683.         (void) cmd_line(strcpy(buf, "next"), msg_list);
  684.         c = 0;
  685.         }
  686.         if (c > -1)
  687.         turnon(glob_flags, CNTD_CMD), redo = 1;
  688.         iscurses = TRUE;
  689.         puts(compose_hdr(current_msg));
  690.  
  691.     /* bind a key or string to a curses-mode command */
  692.     when C_BIND :  case C_UNBIND : case C_MAP : case C_BIND_MACRO :
  693.     case C_MAP_BANG : {
  694.         char *argv[2];
  695.         argv[0] = (c == C_BIND) ? "bind" :
  696.               (c == C_UNBIND) ? "unbind" :
  697.               (c == C_MAP) ? "map" :
  698.               (c == C_MAP_BANG) ? "map!" : "bind-macro";
  699.         argv[1] = NULL;
  700.         if (bind_it(1, argv) < -1)
  701.         turnon(glob_flags, CNTD_CMD);
  702.         else if (ison(glob_flags, CNTD_CMD)) /* if it was set anyway */
  703.         putchar('\n');
  704.         else
  705.         (void) curses_help_msg(TRUE);
  706.     }
  707.  
  708.     when C_MACRO : 
  709.         turnon(glob_flags, IN_MACRO);
  710.         /* Current macro should already be in the mac_stack, so
  711.          * all we have to do here is look for the next character
  712.          */
  713.  
  714.     /* help stuff */
  715.     when C_HELP :
  716.         move(LINES-1, 0), refresh();
  717.         (void) help(0, "curses", cmd_help);
  718.         turnon(glob_flags, CNTD_CMD);
  719.         if (msg_cnt)
  720.         puts(compose_hdr(current_msg));
  721.  
  722.     otherwise :
  723.         mac_flush();
  724.         bell();
  725.         if (ison(glob_flags, CNTD_CMD)) {
  726.         /* use print instead of puts to overwrite hit_return msg */
  727.         print("unknown command"), putchar('\n');
  728.         redo = 1;
  729.         }
  730.     }
  731.  
  732.     if (ison(glob_flags, CNTD_CMD)) {
  733.     int old_cnt = msg_cnt;
  734.     if (!(c = hit_return()) && !redo && msg_cnt == old_cnt)
  735.         redraw();
  736.     clr_bot_line();
  737.     if (old_cnt !=  msg_cnt)
  738.         redo = 1;
  739.     if (c)
  740.         return c;
  741.     }
  742.     if (redo) {
  743.     set_screen_size(); /* it may have changed */
  744.     n = current_msg;
  745.     clear();
  746.     if (/* msg_cnt < screen || */ n_array[0] < n && n < n_array[screen-1])
  747.         (void) do_hdrs(0, DUBL_NULL, NULL);
  748.     else
  749.         (void) cmd_line(sprintf(buf, "\\headers %d", n+1), msg_list);
  750.     (void) curses_help_msg(TRUE);
  751.     redo = 0;
  752.     }
  753.     return 0;
  754. }
  755.  
  756. vrfy_update(redo)
  757. int *redo;
  758. {
  759.     char buf[16];
  760.     int c;
  761.  
  762.     /* update current folder */
  763.     if (ison(glob_flags, DO_UPDATE)) {
  764.     if (ison(glob_flags, READ_ONLY)) {
  765.         mac_flush();
  766.         print("Folder is read-only.");
  767.         if (ison(glob_flags, CNTD_CMD))
  768.         putchar('\n');
  769.         return 0;
  770.     }
  771.     print("Update folder [y]? ");
  772.     if ((c = getchar()) != 'y' && c != 'Y' && c != '\n' && !isspace(c)) {
  773.         print("Folder unchanged.");
  774.         if (ison(glob_flags, CNTD_CMD))
  775.         putchar('\n');
  776.         return 0;
  777.     }
  778.     } else if (*redo)
  779.     return 1;
  780.     if (cmd_line(strcpy(buf, *redo? "update" : "quit"), msg_list) != -1
  781.         && ison(glob_flags, CNTD_CMD))
  782.     *redo = 1, turnoff(glob_flags, CNTD_CMD);
  783.     turnoff(glob_flags, DO_UPDATE);
  784.     return 1; /* make sure bottom line is clear and no reverse video */
  785. }
  786.  
  787. scrn_line(line, buf)
  788. char *buf;
  789. {
  790. #ifndef A_CHARTEXT
  791.     (void) strncpy(buf, stdscr->_y[line], COLS-1);
  792.     buf[COLS-1] = 0; /* strncpy does not null terminate */
  793. #else
  794.     int n;
  795.  
  796.     for (n = 0; n < COLS; n++)
  797.     if ((buf[n] = (mvinch(line, n) & A_CHARTEXT)) == '\0')
  798.         break;
  799.     buf[n] = '\0';
  800. #endif /* A_CHARTEXT */
  801. }
  802.  
  803. /*
  804.  * Generate the help message from the variable curses_help.
  805.  *  If visible is true, the message is displayed,
  806.  *  otherwise its size (in lines) is computed and returned.
  807.  */
  808. curses_help_msg(visible)
  809. int visible;
  810. {
  811.     int count, i, len, siz = 0, mxm = 0;
  812.     static int old_siz = 0;
  813.     register struct cmd_map *list;
  814.     extern struct cmd_map map_func_names[];
  815.     char *curs_help = do_set(set_options, "curses_help"), **format;
  816.  
  817.     if (!curs_help) {
  818.     if (old_siz && visible) {
  819.         int bot = min(n_array[screen-1], msg_cnt-1);
  820.         move(max(0, bot - n_array[0]) + 2, 0), clrtobot();
  821.         old_siz = 0;
  822.     }
  823.     return 0;
  824.     } else if (!*curs_help)
  825.     curs_help = DEF_CURSES_HELP;
  826.     /* Split the help string into words */
  827.     if (!(format = mk_argv(curs_help, &count, FALSE)) || count <= 0)
  828.     return 0;
  829.     /* Generate a help message for each word */
  830.     for (i = 0; i < count; i++) {
  831.     char buf[MAX_BIND_LEN*2+MAX_LONG_CMD+5], asc[MAX_BIND_LEN*2];
  832.  
  833.     buf[0] = '\0'; /* default to empty in case of no match */
  834.     for (list = cmd_map; list; list = list->m_next) {
  835.         if (!strcmp(format[i], map_func_names[list->m_cmd].m_str)) {
  836.         len = strlen(sprintf(buf, "(%s) %s  ",
  837.                 ctrl_strcpy(asc, list->m_str, FALSE),
  838.                 map_func_names[list->m_cmd].m_str));
  839.         if (len > mxm)
  840.             mxm = len;
  841.         break;
  842.         }
  843.     }
  844.     strdup(format[i], buf); /* replace word with its "definition" */
  845.     }
  846.     /* Columnate the output nicely */
  847.     if (mxm > 0) {
  848.     len = (COLS - 1) / mxm;
  849.     if (len == 0) {
  850.         if (visible)
  851.         print("Curses help message too long!");
  852.         return 0;
  853.     }
  854.     siz = count / len;
  855.     if (count % len)
  856.         siz++;
  857.     if (siz > LINES / 3) {
  858.         if (visible)
  859.         print("Curses help message too long!");
  860.         return 0;
  861.     }
  862.     if (visible) {
  863.         int next = LINES - 1 - siz;
  864.         if (old_siz > siz) {
  865.         int bot = min(n_array[screen-1], msg_cnt-1);
  866.         move(max(0, bot - n_array[0]) + 2, 0), clrtobot();
  867.         }
  868.         old_siz = siz;
  869.         for (i = 0; i < count; i++) {
  870.         if (!(i % len))
  871.             move(next, 0), clrtoeol(), ++next;
  872.         if (format[i][0])
  873.             printw("%-*.*s", mxm, mxm, format[i]);
  874.         }
  875.         refresh();
  876.     }
  877.     }
  878.     free_vec(format);
  879.     return siz;
  880. }
  881.  
  882. set_screen_size()
  883. {
  884.     int hlp_siz = LINES - 2 - curses_help_msg(FALSE); 
  885.  
  886.     if (!do_set(set_options, "screen"))
  887. #ifdef USG
  888.     switch (_tty.sg_ospeed & CBAUD)
  889. #else /* USG */
  890.     switch (_tty.sg_ospeed)
  891. #endif /* USG */
  892.     {
  893.         case B300 :  screen = min(hlp_siz, 7);
  894.         when B1200 : screen = min(hlp_siz, 14);
  895.         when B2400 : screen = min(hlp_siz, 22);
  896.         otherwise :  screen = hlp_siz;
  897.     }
  898.     else
  899.     screen = min(screen, hlp_siz);
  900. }
  901.  
  902. /*
  903.  * prompt for a carriage return, but return whatever user types unless
  904.  * it's a character which he might regret (like 'q' or 'x'). Ignore
  905.  * interrupts (kind of) because we have nowhere to longjmp to.  When we
  906.  * return, we'll setjmp again (top of loop.c)
  907.  */
  908. hit_return()
  909. {
  910.     int c;
  911.  
  912.     turnon(glob_flags, IGN_SIGS);
  913.     iscurses = FALSE;
  914.     (void) check_new_mail();
  915.     iscurses = TRUE;
  916.     mail_status(1), addstr("...continue... "), refresh();
  917.     c = getcmd();
  918.     turnoff(glob_flags, IGN_SIGS);
  919.  
  920.     /* don't let the user type something he might regret */
  921.     if (c == C_QUIT || c == C_EXIT)
  922.     return C_NULL;
  923.     return c;
  924. }
  925.  
  926. curses_msg_list(str, list, m_list)
  927. register char *str, *list;
  928. char m_list[];
  929. {
  930.     register char *p = NULL;
  931.     int c, sv_cur_msg = current_msg;
  932.  
  933.     print(str);
  934.     c = Getstr(list, COLS-13, 0);
  935.     move(LINES-1, 0), refresh();
  936.     if (c <= 0 || !(p = do_range(list, m_list)) ||
  937.     (p == list && *p && *p != '$' && *p != '^')) {
  938.     if (p)
  939.         print("Invalid message list: %s", p);
  940.     current_msg = sv_cur_msg;
  941.     return 0;
  942.     }
  943.     current_msg = sv_cur_msg;
  944.     return 1;
  945. }
  946.  
  947. curs_vars(which)
  948. int which;  /* really, a char */
  949. {
  950.     char c, buf[128], buf2[128], *string;
  951.     struct options **list;
  952.  
  953.     switch(which) {
  954.     case C_OWN_HDR : string = "my_hdr", list = &own_hdrs;
  955.     when C_ALIAS : string = "alias", list = &aliases;
  956.     when C_IGNORE : string = "ignore", list = &ignore_hdr;
  957.     when C_VAR_SET : string = "set", list = &set_options;
  958.     otherwise : clr_bot_line(); return;
  959.     }
  960.  
  961.     print("%s [? Set Unset All]: ", string);
  962.     c = m_getchar();
  963.     clr_bot_line();
  964.     switch (Lower(c)) {
  965.     /* if help, print help -- if "all", show all settings. */
  966.     case '?' : case 'a' :
  967.         if (c == '?') {
  968.         if (!strcmp(string, "set")) {
  969.             print("which variable? [all <var>]: ");
  970.             if ((c = Getstr(buf+1, COLS-40, 0)) < 0)
  971.             return;
  972.             clr_bot_line();
  973.             buf[0] = '?';
  974.             if (c > 0) {
  975.             char *argv[3];
  976.             argv[0] = string;
  977.             argv[1] = buf;
  978.             argv[2] = NULL;
  979.             Lower(buf[1]);
  980.             if (!strcmp(buf+1, "a"))
  981.                 (void) strcpy(buf+1, "all");
  982.             if (!strcmp(buf+1, "all"))
  983.                 turnon(glob_flags, CNTD_CMD);
  984.             (void) set(2, argv, (char *) 0);
  985.             break;
  986.             }
  987.         }
  988.         /* help returns next command (hit_return) */
  989.         (void) help(0, string, cmd_help);
  990.         turnon(glob_flags, CNTD_CMD);
  991.         return;
  992.         }
  993.         turnon(glob_flags, CNTD_CMD);
  994.         (void) do_set(*list, NULL);
  995.  
  996.     /* if set, prompt for string and let user type */
  997.     when 's' :
  998.         print("set: ");
  999.         c = Getstr(buf, COLS-18, 0);
  1000.         clr_bot_line();
  1001.         if (c > 0)
  1002.         (void) cmd_line(sprintf(buf2, "%s %s", string, buf), msg_list);
  1003.  
  1004.     /* if unset, just as easy as set! */
  1005.     when 'u' :
  1006.         print("unset: ", string);
  1007.         if (Getstr(buf, COLS-18, 0) > 0 && !un_set(list, buf))
  1008.         print("%s isn't set", buf);
  1009.     }
  1010.     if (ison(glob_flags, CNTD_CMD))
  1011.     putchar('\n');
  1012.     else
  1013.     (void) curses_help_msg(TRUE);
  1014. }
  1015. #endif /* CURSES */
  1016.